function getAbsolutePosition(element) {
    var r = { x: element.offsetLeft, y: element.offsetTop };
    if (element.offsetParent) {
      var tmp = getAbsolutePosition(element.offsetParent);
      r.x += tmp.x;
      r.y += tmp.y;
    }
    return r;
}

function PagePosition(evt) {
  if (evt.pageX)
    return { x: evt.pageX, y: evt.pageY };
  else // Internet explorer
    return { 
      x: evt.clientX + document.body.parentNode.scrollLeft + document.body.scrollLeft,
      y: evt.clientY + document.body.parentNode.scrollTop + document.body.scrollTop 
    };
}

// FIXME: final position gets miscomputed at the beginning...
function MakeImageScroller(d, src) {
  if (typeof(d) == "string") d = document.getElementById(d);
  d.style.overflow = 'hidden';
  var img = document.createElement('img');
  var imgw = 0, imgh = 0;
  img.onload = function () {
    imgw = img.width;
    imgh = img.height;
    img.width = d.offsetWidth;
    img.height = (d.offsetWidth / imgw) * imgh;
  }
  img.src = src;
  img.style.position = 'relative';
  d.appendChild(img);
  var t = null, z = null;
    

  d.onmouseover = function (e) {
    if (z) z.Stop();
    var speed = 1;        
    z = new Timeline();
    z.SetAt(0, AnimeJInterp.px(imgw * speed, 60, img.style, 'width', img.offsetWidth, imgw));
    z.SetAt(0, AnimeJInterp.px(imgw * speed, 60, img.style, 'height', img.offsetHeight, imgh));
    z.SetAt(0, AnimeJInterp.px(imgw * speed, 60, img.style, 'left', 0, - (imgw - d.offsetWidth) / 2));
    z.SetAt(0, AnimeJInterp.px(imgw * speed, 60, img.style, 'top', 0, - (imgh - d.offsetHeight) / 2));
    z.OnEnd = function () { z = null; }
    z.Run();
  }
    
  d.onmouseout = function (e) {
    if (t) t.Stop();
    if (z) z.Stop();
    var speed = 1;
    z = new Timeline();
    z.SetAt(0, AnimeJInterp.px(imgw * speed, 60, img.style, 'width', imgw, d.offsetWidth));
    z.SetAt(0, AnimeJInterp.px(imgw * speed, 60, img.style, 'height', imgh, (d.offsetWidth / imgw) * imgh));
    z.SetAt(0, AnimeJInterp.px(imgw * speed, 60, img.style, 'left', parseInt(img.style.left), 0));
    z.SetAt(0, AnimeJInterp.px(imgw * speed, 60, img.style, 'top', parseInt(img.style.top), 0));    
    z.OnEnd = function () { z = null; }
    z.Run();
  }
   
  var oldtgtx = 0, oldtgty = 0;
  d.onmousemove = function (e) {
    if (z) return;
    var mpos = PagePosition(e ? e : window.event);
	var pos = getAbsolutePosition(d);
    var x = mpos.x - pos.x;
    var y = mpos.y - pos.y;

    var srcX = img.style.left ? parseInt(img.style.left) : 0;
    var srcY = img.style.top ? parseInt(img.style.top) : 0;
		
    var srcW = img.offsetWidth, srcH = img.offsetHeight;
    var tgtW = d.offsetWidth, tgtH = d.offsetHeight;

    var tgtX = -(x / tgtW)*(srcW - tgtW + 1);
    var tgtY = -(y / tgtH)*(srcH - tgtH + 1);
    
    if (t && (Math.sqrt((tgtX - oldtgtx) * (tgtX - oldtgtx) + (tgtY - oldtgty) * (tgtY - oldtgty)) < 25)) return;
    
    oldtgtx = tgtX;
    oldtgty = tgtY;
      
    var speed = 1.1; // 100px / 100ms
    
    if (t) t.Stop();
    t = new Timeline();
    t.SetAt(0, AnimeJInterp.px(Math.abs(tgtX - srcX)*speed, 60, img.style, 'left', srcX, tgtX));
    t.SetAt(0, AnimeJInterp.px(Math.abs(tgtY - srcY)*speed, 60, img.style, 'top', srcY, tgtY));
    t.OnEnd = function () { t = null; };
    t.Run();
  }
}
